package com.ruoyi.model.apect;

import com.alibaba.fastjson2.JSON;
import com.ruoyi.common.annotation.SystemLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Optional;

/**
 * @author : 张怀秋
 **/
@Slf4j
@Aspect
@Component
public class SystemLogAspect {

    /**
     * 表示以后SystemLog的标识的注解都会用到增强功能
     */
    @Pointcut("@annotation(com.ruoyi.common.annotation.SystemLog)") //切入点
    public void pt() {

    }

    /**
     * 表示这个环绕通知具体使用的方法是哪一个方法
     *
     * @param joinPoint 连接点 表示被争抢的方法
     * @return Object
     */
    @Around("pt()")
    public Object printLog(ProceedingJoinPoint joinPoint) throws Throwable { //这里的异常要往外抛 让统一异常处理掉而不是这里
        Object result;
        try {
            handleBefore(joinPoint); //处理之前的打印
            result = joinPoint.proceed();
            handlerAfter(result); //处理之后的打印
        } finally {
            // 结束后换行
            log.info("finally必须执行表示日志记录结束" + System.lineSeparator());
        }
        return result;
    }

    /**
     * 前置输出
     *
     * @param joinPoint 连接点
     */
    private void handleBefore(ProceedingJoinPoint joinPoint) {
        //1.获取request
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();

        HttpServletRequest request = null;
        if (requestAttributes != null) {
            request = requestAttributes.getRequest();
        }

        //2.准备获取注解 使用薛定谔的盒子
        Optional<SystemLog> anno = getAnno(joinPoint);

        //3.盒子中的猫没有死 那么打印日志
        if (anno.isPresent()) {
            String businessName = anno.get().businessName();
            log.info("=======Start=============================");
            //打印Url
            assert request != null;
            log.info("URL               : {}", request.getRequestURI());
            //打印描述信息
            log.info("当前方法的功能       : {}", businessName);
            //打印ip地址
            log.info("当前访问Ip         : {}", request.getRemoteAddr());
            //打印方法名
            log.info("当前执行的请求方式   : {}", request.getMethod());
            // 打印调用 controller 的全路径以及执行方法
            log.info("方法的全类名   : {}.{}", joinPoint.getSignature().getDeclaringTypeName(), (joinPoint.getSignature()).getName());
            // 打印请求入参
            log.info("请求入参  : {}", JSON.toJSON(joinPoint.getArgs()));
            // 结束后换行
            log.info("=======End==============================" + System.lineSeparator());
        }
    }

    private Optional<SystemLog> getAnno(ProceedingJoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        SystemLog annotation = signature.getMethod().getAnnotation(SystemLog.class);
        if (annotation != null) {
            return Optional.of(annotation);
        }
        return Optional.empty();
    }

    /**
     * @param result 处理之后的结果
     */
    private void handlerAfter(Object result) {
        // 打印出参
        log.info("Response       : {}", JSON.toJSON(result));
    }


}
